<?php

declare(strict_types=1);

/**
 * @Author:     Frank
 * @contact     frank_hhm@163.com
 * @Date:       2022-11-28 14:16:52
 * @Last Modified time: 2023-02-17 16:34:17
 */

namespace frank\services;

use think\facade\Db;
use think\facade\App;
use think\facade\Cache;
use think\facade\Request;
use think\facade\Filesystem;
use think\exception\ValidateException;
use Intervention\Image\ImageManagerStatic;
use frank\utils\helper\ArrayHelper;
use frank\exception\CommonException;
use frank\services\CacheService;
use think\File;

/**
 * 文件上传
 * Class FileUploadService
 * @package frank\service
 */
class FileUploadService extends \frank\base\BaseService
{
    
    public $upload_path = __UPLOAD__;//公共上传文件

    public $path;//上传路径

    public $config = []; //上传配置

    public $oss_type = []; //存储引擎

    public $rule_type;//允许上传 mime类型

    public $rule_ext;// 允许上传 文件后缀


    public function __construct()
    {
        $this->path = $this->upload_path . "/";
    }

    public function imagem($param = [])
    {
        try {
            $this->checkImg();
            $file = request()->file($param[ "name" ]);
            if (empty($file)){
                throw new CommonException('上传失败：文件为空');
            }
            $tmp_name = $file->getPathname();//获取上传缓存文件
            $original_name = $file->getOriginalName();//文件原名

            $file_path = $this->path;
            // 检测目录
            $this->checkPath($file_path);//验证写入文件的权限
            $createname = $this->createNewFileName();
            $file_name = $file_path . $createname;
            $extend_name = $file->getOriginalExtension();

            $thumb_type = $param[ "thumb_type" ] ?? [];
            //原图保存
            $new_file = $file_name . "." . $extend_name;
            $image = ImageManagerStatic::make($tmp_name);
            $width = $image->width();//图片宽
            $height = $image->height();//图片高
            // 是否需生成水印
            $image = $this->imageWater($image);
            $file_result = $this->imageCloud($image, $new_file);//原图云上传(文档流上传)

            $pic_name_first = substr(strrchr($original_name, '.'), 1);
            $former_name = basename($original_name, "." . $pic_name_first);
            $fileInfo = [
                'oss_type'  => $file_result['oss_type'] ?? 'local',
                'file_path' => $file_result['path'] ??  $file_result,
                'file_size' => $file->getSize(),
                'file_name' => $createname,
                'former_name' => $former_name,
                'file_type' => substr($file->getMime(),0,strrpos($file->getMime(),"/")),
                'extension' => substr($file->getMime(),strripos($file->getMime(),"/")+1),
                'file_domain'=>$file_result['domain'] ?? '',
                'create_time'=>time(),
                "pic_spec" => $width . "*" . $height
            ];
            if(!empty($param[ "source_id" ])){
                $fileInfo['group_id']=$param[ "group_id" ] ?? 0;
                $fileInfo['source_id']=$param[ "source_id" ];
                $fileInfo['source']= $param[ "source" ];
                Db::name('mate_files')->save($fileInfo);
            }
            $fileInfo['file_url'] = ($fileInfo['oss_type'] == 'local'?Request::instance()->domain():$fileInfo['file_domain'] ) .'/'. $fileInfo['file_path'];
            return $fileInfo;
        } catch (think\exception\ValidateException $e) {
            throw new CommonException($e->getMessage());
        }
    }

    /**
     * 验证目录是否可写
     * @param unknown $path
     * @return boolean
     */
    public function checkPath($path)
    {
        if (file_exists($path) || mkdir($path, 0755, true)) {
            return true;
        }
        throw new CommonException("directory {$path} creation failed");
    }

    /**
     * 设置上传目录
     * @param $path
     */
    public function setPath($path)
    {
        $this->path = $path;
        $this->path = $this->upload_path . "/" . $this->path . "/";
        return $this;
    }

    /**
     *获取一个新文件名
     */
    public function createNewFileName()
    {
        $name = date('Ymdhis', time())
            . sprintf('%03d', microtime(true) * 1000)
            . sprintf('%02d', mt_rand(10, 99));
        return $name;
    }


    /**
     * 图片验证
     * @param $file
     * @return \multitype
     */
    public function checkImg()
    {
        try {
            $file = request()->file();
            $rule_array = [];
            $size_rule = sysconf('max_filesize');
            $ext_rule =  sysconf('image_allow_ext');
            $mime_rule = sysconf('image_allow_mime');

            if (!empty($size_rule)) {
                $rule_array[] = "fileSize:{$size_rule}";
            }
            if (!empty($ext_rule)) {
                $rule_array[] = "fileExt:{$ext_rule}";
            }
            if (!empty($mime_rule)) {
                $rule_array[] = "fileMime:{$mime_rule}";
            }
            if (!empty($rule_array)) {
                $rule = implode("|", $rule_array);
                validate([ 'file' => $rule ])->check($file);
            }
        } catch (\think\exception\ValidateException $e) {
            throw new CommonException($e->getMessage());
        }
    }


    /**
     * 删除文件
     * @param $file_name
     */
    private function deleteFile($file_name)
    {
        $res = @unlink($file_name);
        if ($res) {
            return true;
        } else {
            return false;
        }

    }

    /**
     * 图片云上传中转
     * @param $image
     * @param $file
     * @return array|mixed|string
     */
    public function imageCloud($image, $file)
    {
        try {
            $image->save($file);
            $result = $this->fileCloud($file);
            //云上传没有成功  保存到本地
            return $result;
        } catch (\Exception $e) {
            throw new CommonException($e->getMessage());
        }

    }

    /**
     * 云上传
     */
    public function fileCloud($file)
    {
        try {
            //走 云上传
            $put_result = event("Put", [ "file_path" => $file, "key" => $file ], true);
            if (!empty($put_result)) {
                $this->deleteFile($file);
                return $put_result;
            }
            //云上传没有成功  保存到本地
            return $file;
        } catch (\Exception $e) {
            throw new CommonException($e->getMessage());
        }
    }

    /**
     * 添加水印
     */
    public function imageWater($image)
    {
        return $image;
    }

    /**
     * 设置缓存目录
     */
    public function setCachePath($path){
        $this->upload_path = root_path().'runtime';
        $this->path = $path;
        $this->path = $this->upload_path . "/" . $this->path . "/";
        return $this;
    }

    public function cacheImagem($param = []){
        try {
            $this->checkImg();
            $file = request()->file($param[ "name" ]);
            if (empty($file)){
                throw new CommonException('上传失败：文件为空');
            }
            $tmp_name = $file->getPathname();//获取上传缓存文件
            $original_name = $file->getOriginalName();//文件原名

            $file_path = $this->path;
            // 检测目录
            $this->checkPath($file_path);//验证写入文件的权限
            $createname = $this->createNewFileName();
            $file_name = $file_path . $createname;
            $extend_name = $file->getOriginalExtension();
            //原图保存
            $new_file = $file_name . "." . $extend_name;
            $image = ImageManagerStatic::make($tmp_name);
            // 是否需生成水印
            $image = $this->imageWater($image);
            $image->save($new_file);
            $token = md5($createname);
            // 暂存缓存里
            $cacheService = CacheService::instance();
            $cacheService->setTokenBucket('files_token:'.$token,$new_file,60*60*24);
            return $createname;
        } catch (think\exception\ValidateException $e) {
            throw new CommonException($e->getMessage());
        }
    }

    /**
     * 缓存图片移至永久
     */
    public function moveCacheFiles($fileNames = [],$pathName = '',$returnArray = false){
        $cacheService = CacheService::instance();
        $pathName = $this->path.$pathName;
        $filesArr = [];
        foreach ($fileNames as $key => $item) {
            $filePath = $cacheService->getTokenBucket('files_token:'.md5($item));
            if(empty($filePath)){
                throw new CommonException('缓存文件已过期');
            }
            $image = new File($filePath);
            $res = $image->move($pathName);
            $filesArr[] = '/'.$res->getPathName();
        }
        if ($returnArray) {
            return $filesArr;
        }
        return implode(',', $filesArr);
    }

}